using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Instrumentation;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml;
using System.Xml.Serialization;
using CoreClasses;
using LayoutPlanning.Helpers;
using LayoutPlanning.Model.ImmaModels;
using LayoutPlanning.ViewModel;
using LayoutPlanning.Views.Machines;
using Microsoft.Win32;
using RelayCommand = LayoutPlanning.Helpers.RelayCommand;


namespace LayoutPlanning.Model
{
    [Serializable]
    public class Station : GraficalObject, IComparable<Station>
    {
        private Loudness _loudness = Loudness.Quiet;

        private double _negativeInfluence;
        private ObservableDragableObject _selectedWorkGripPosition;
        private bool _soundSensitiv;

        [NonSerialized] private DispatcherOperation dispa;

        [NonSerialized] private string _syncedText = "Save";

        private string _syncId = Guid.NewGuid().ToString();


        public Station()
        {
            WorkPositions.Add(new WorkPosition());
            PropertyChanged += Origo_PropertyChanged;
        }

        protected Station(SerializationInfo info, StreamingContext context)
        {
        }

        public ObservableCollection<WorkPosition> WorkPositions { get; } = new ObservableCollection<WorkPosition>();

        public RelayCommand AddWorkPosition
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var station = this;
                    string posname = "New Workposition";
                    int i = 0;
                    var posname1 = posname;
                    while (station.WorkPositions.Any(t => t.Name == posname1))
                    {
                        i++;
                        posname1 = posname + i;
                    }
                    posname += i == 0 ? "" : i + "";
                    var wpos = new WorkPosition(posname, new Point(), 0);
                    station.WorkPositions.Add(wpos);
                    station.SelectedWorkGripPosition = wpos;
                });
            }
        }

        public double NegativeInfluence
        {
            get { return _negativeInfluence; }
            set
            {
                _negativeInfluence = value;
                RaisePropertyChanged();
            }
        }

        public Loudness Loudness
        {
            get { return _loudness; }
            set
            {
                _loudness = value;
                RaisePropertyChanged();
                RaisePropertyChanged(nameof(SoundColor));
            }
        }

        [XmlIgnore]
        public Brush SoundColor
        {
            get
            {
                switch (Loudness)
                {
                    case Loudness.Loud:
                        return Brushes.OrangeRed;
                    case Loudness.Disturbing:
                        return Brushes.Orange;
                    case Loudness.Moderate:
                        return Brushes.GreenYellow;
                    default:
                        return Brushes.Transparent;
                }
            }
        }

        public bool SoundSensitiv
        {
            get { return _soundSensitiv; }
            set
            {
                _soundSensitiv = value;
                RaisePropertyChanged();
            }
        }

        public IEnumerable<KeyValuePair<Station, double>> ResourceRelation
        {
            get
            {
                var q =
                    ViewModelLocator.Main.Model.DeployedGraficalObjects.Where(
                        t => t != this && t.GetType() == typeof(Station)).Cast<Station>();
                var Rand = new Random();
                return q.Select(t => new KeyValuePair<Station, double>(t, Rand.Next(-10, 10))).Distinct();
            }
        }


        public ObservableDragableObject SelectedWorkGripPosition
        {
            get { return _selectedWorkGripPosition; }
            set
            {
                _selectedWorkGripPosition = value;
                RaisePropertyChanged();
                RaisePropertyChanged(nameof(SelectedWorkPosition));
                RaisePropertyChanged(nameof(SelectedGripPosition));
            }
        }

        public WorkPosition SelectedWorkPosition => _selectedWorkGripPosition as WorkPosition;

        public ObservableCollection<GripPointModel> GripPositions { get; } = new ObservableCollection<GripPointModel>();

        public GripPointModel SelectedGripPosition => _selectedWorkGripPosition as GripPointModel;

        public RelayCommand AddGripPosition
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var station = this;
                    string posname = "New Grippoint";
                    int i = 0;
                    var posname1 = posname;
                    while (station.GripPositions.Any(t => t.Name == posname1))
                    {
                        i++;
                        posname1 = posname + i;
                    }
                    posname += i == 0 ? "" : i + "";
                    var wpos = new GripPointModel()
                    {
                        Name = posname,
                        GripType = GripTypes.Normal,
                        Position = new Point()
                    };

                    station.GripPositions.Add(wpos);
                    station.SelectedWorkGripPosition = wpos;
                });
            }
        }

        public RelayCommand ImportGrafics => new RelayCommand(() =>
        {
            OpenFileDialog openfile = new OpenFileDialog();
            openfile.FileName = "layout";
            openfile.DefaultExt = ".dxf";
            openfile.InitialDirectory = Directory.GetCurrentDirectory();
            openfile.Filter = "Autocad DXF Files (.dxf)|*.dxf";
            if (openfile.ShowDialog() ?? false)
            {

                try
                {
                    IList<Shape> childs = null;
                    if (openfile.FileName.EndsWith(".wrl"))
                        childs = DFXImporter.LoadVrml(openfile.FileName);

                    if (openfile.FileName.EndsWith(".dxf"))
                        childs = DFXImporter.LoadDxf(openfile.FileName, 1000);
                    if (childs == null)
                        throw new Exception("Error Loading File");
                    var newcontrol = new UserControl()
                    {
                        VerticalAlignment = VerticalAlignment.Stretch,
                        HorizontalAlignment = HorizontalAlignment.Stretch
                    };
                    newcontrol.Content = new Canvas()
                    {
                        VerticalAlignment = VerticalAlignment.Stretch,
                        HorizontalAlignment = HorizontalAlignment.Stretch
                    };
                    double minLeft = childs.OfType<Line>().Min(i => Math.Min(i.X1, i.X2));
                    double maxLeft = childs.OfType<Line>().Max(i => Math.Max(i.X1, i.X2));
                    double minTop = childs.OfType<Line>().Min(i => Math.Min(i.Y1, i.Y2));
                    double maxTop = childs.OfType<Line>().Max(i => Math.Max(i.Y1, i.Y2));
                    //(newcontrol.Content as Canvas).Width = maxLeft - minLeft;
                    //(newcontrol.Content as Canvas).Height = maxTop - minTop;
                    // newcontrol.Width = maxLeft - minLeft;
                    // newcontrol.Height = maxTop - minTop;
                    //newcontrol.VerticalAlignment
                    foreach (var child in childs)
                    {
                        (newcontrol.Content as Canvas).Children.Add(child);
                    }
                    SetCustomControl(newcontrol);
                    //Control = new SerializableFrameworkElement(newcontrol);
                    SizeX = maxLeft - minLeft;
                    SizeY = maxTop - minTop;
                }
                catch (Exception e)
                {
                    MessageBox.Show(
                        "Error loading the file. Is it empty or wrong format? This program can import lines in a dxf file format.\n" +
                        e.Message);
                }


            }
        });


        public int CompareTo(Station other)
        {
            return String.Compare(Name, other.Name, StringComparison.Ordinal);
        }

        private void Origo_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            foreach (var workPosition in WorkPositions)
            {
                workPosition.Origo = Origo;
            }
            foreach (var workPosition in GripPositions)
            {
                workPosition.Origo = Origo;
            }
        }


        public override Task<GraficalObject> Copy()
        {
            var disp = new Station()
            {
                Position = Position,
                Loudness = Loudness,
                Name = Name,
                NegativeInfluence = NegativeInfluence,
                SizeX = SizeX,
                SizeY = SizeY,
                SoundSensitiv = SoundSensitiv,
                ControlType = ControlType,
                NormalColorString = NormalColorString

            };
            disp.dispa = Dispatcher.CurrentDispatcher.InvokeAsync(() =>
            {
                var d = disp;

                if (ControlType == ControlType.Custom)
                {
                    if (CustomControl != null)
                        d.SetCustomControl(CustomControl.XamlSyncClone().Element);
                    else
                    {
                        ControlType = ControlType.Square;
                    }
                }

            }, DispatcherPriority.ContextIdle);

            return Task.Run(() => disp as GraficalObject);
        }

        [XmlIgnore]
        public string SyncedText
        {
            get { return _syncedText; }
            set
            {
                _syncedText = value;
                RaisePropertyChanged();
            }
        }

        public string SyncID
        {
            get { return _syncId; }
            set { _syncId = value; }
        }

        public RelayCommand SaveUpdate => new RelayCommand(() =>
        {
#if DEBUG
            var service = new CollaborationService.ServiceContractClient("BasicHttpsBinding_IServiceContractDebug");
#else
            var service = new CollaborationService.ServiceContractClient("BasicHttpsBinding_IServiceContract");
#endif
            if (SyncedText == "Update")
            {
                service.DeleteGeneralStation(SyncID);
            }
            service.AddGeneralStation(new CollaborationService.Station()
            {
                Color = NormalColorString,
                Control = CustomControl?.GetContractData()?.Binary,
                ControlType = ControlType.ToString(),
                SizeX = SizeX,
                SizeY = SizeY,
                SyncId = SyncID,
                Name = Name

            });
            SyncedText = "Update";

        });

    }

    public enum Loudness
    {
        Quiet = 0,
        Moderate = 1,
        Disturbing = 2,
        Loud = 3
    }

    
}